package flash3.net
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.Socket;
	import flash.utils.Endian;
	import flash.utils.getTimer;
	
	import flash3.net.Encrypt;
	import flash3.net.MsgPacket;

	public class BaseConnect extends EventDispatcher
	{
		private var _socket:Socket = null;;
		private var _packSize:uint;
		private var _needHead:Boolean = true;;
		private var _sendQueue:Array = [];
		private var _reciveQueue:Array = [];
		
		public function BaseConnect()
		{
		}
		
		public function connect(host:String, port:int):void
		{
			reset();
			_socket = new Socket();
			_socket.endian = Endian.LITTLE_ENDIAN;
			_socket.addEventListener(Event.CONNECT, onConnectSucceed);
			_socket.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
			_socket.addEventListener(Event.CLOSE, onConnectClose);
			_socket.addEventListener(ProgressEvent.SOCKET_DATA, onReciveData);
			_socket.connect(host, port);
		}
		
		public function close():void
		{
			if(_socket && _socket.connected)
				_socket.close();
		}
		
		public function onConnectSucceed(evt:Event):void
		{
			_socket.removeEventListener(Event.CONNECT, onConnectSucceed);
			dispatchEvent(evt);
		}
		
		public function onIOError(evt:IOErrorEvent):void
		{
			_socket.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
			dispatchEvent(evt);
		}
		
		public function onSecurityError(evt:SecurityErrorEvent):void
		{
			_socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
			dispatchEvent(evt);
		}
		
		public function onConnectClose(evt:Event):void
		{
			_socket.removeEventListener(Event.CLOSE, onConnectClose);
			dispatchEvent(evt);
		}
		
		public function onReciveData(evt:Event):void
		{
			var packet:MsgPacket = null;
			while(packet = getPacket())
			{
				_reciveQueue.push(packet);
				reciveQueue();
			}
		}
		
		private function getPacket():MsgPacket
		{
			if(!_socket) return null;
			
			if(_needHead)
			{
				if(_socket.bytesAvailable < 2)
					return null;
				
				_packSize = _socket.readShort();
				_needHead = false;
			}
			
			if(_socket.bytesAvailable >= _packSize-2)
			{
				var data1:ByteArrayPlus = new ByteArrayPlus();
				var data2:ByteArrayPlus = new ByteArrayPlus();
				data1.endian = Endian.LITTLE_ENDIAN;
				data2.endian = Endian.LITTLE_ENDIAN;
				data1.writeShort(_packSize);
				_socket.readBytes(data2, 0, _packSize-2);
				data1.writeBytes(data2);
				_needHead = true;
				return decrypt(data1);
			}
			return null;
		}
		
		public function send(packet:MsgPacket):void
		{
			if (_socket.connected)
			{
				var bap:ByteArrayPlus = encrypt(packet);
				_sendQueue.push(bap);
				sendQueue();
				var evt:PacketEvent = new PacketEvent(PacketEvent.SOCKET_SEND);
				evt._packet = packet;
				dispatchEvent(evt);
			}
		}
		private function recive(packet:MsgPacket):void
		{
			var evt:PacketEvent = new PacketEvent(ProgressEvent.SOCKET_DATA);
			evt._packet = packet;
			dispatchEvent(evt);
		}
		private function sendQueue():void
		{
			while(_sendQueue.length > 0)
			{
				var bap:ByteArrayPlus = _sendQueue.pop() as ByteArrayPlus;
				_socket.writeBytes(bap, 0, bap.length);
				_socket.flush();
			}
		}
		private function reciveQueue():void
		{
			while(_reciveQueue.length > 0)
			{
				recive(_reciveQueue.pop() as MsgPacket);
			}
		}
		
		private function reset():void
		{
			m_dwSendXorKey= 0x12345678;
			m_dwSendXorKey = 0x12345678;
			m_cbSendRound = 0;
			m_cbRecvRound= 0;
			m_dwSendPacketCount = 0;
			_reciveQueue.length = 0;
			_sendQueue.length = 0;
			_needHead = true;
			if(_socket)
			{
				_socket.removeEventListener(Event.CONNECT, onConnectSucceed);
				_socket.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
				_socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
				_socket.removeEventListener(Event.CLOSE, onConnectClose);
				_socket.removeEventListener(ProgressEvent.SOCKET_DATA, onReciveData);
				_socket = null;
			}
		}
		
//////////////加密//////////////////////////////////////////////////////////////////////////////////////////////////////////////		
		public var m_dwSendXorKey:uint = 0x12345678;
		public var m_dwRecvXorKey:uint = 0x12345678;
		public var m_cbSendRound:uint = 0;
		public var m_cbRecvRound:uint = 0;
		public var m_dwSendPacketCount:uint = 0;
		public static const BYTE_COUNT_32:Number = 4;
		
		//发送字节映射表
		private static const m_SendByteMap:Array =
			[
				0x70,0x2F,0x40,0x5F,0x44,0x8E,0x6E,0x45,0x7E,0xAB,0x2C,0x1F,0xB4,0xAC,0x9D,0x91,
				0x0D,0x36,0x9B,0x0B,0xD4,0xC4,0x39,0x74,0xBF,0x23,0x16,0x14,0x06,0xEB,0x04,0x3E,
				0x12,0x5C,0x8B,0xBC,0x61,0x63,0xF6,0xA5,0xE1,0x65,0xD8,0xF5,0x5A,0x07,0xF0,0x13,
				0xF2,0x20,0x6B,0x4A,0x24,0x59,0x89,0x64,0xD7,0x42,0x6A,0x5E,0x3D,0x0A,0x77,0xE0,
				0x80,0x27,0xB8,0xC5,0x8C,0x0E,0xFA,0x8A,0xD5,0x29,0x56,0x57,0x6C,0x53,0x67,0x41,
				0xE8,0x00,0x1A,0xCE,0x86,0x83,0xB0,0x22,0x28,0x4D,0x3F,0x26,0x46,0x4F,0x6F,0x2B,
				0x72,0x3A,0xF1,0x8D,0x97,0x95,0x49,0x84,0xE5,0xE3,0x79,0x8F,0x51,0x10,0xA8,0x82,
				0xC6,0xDD,0xFF,0xFC,0xE4,0xCF,0xB3,0x09,0x5D,0xEA,0x9C,0x34,0xF9,0x17,0x9F,0xDA,
				0x87,0xF8,0x15,0x05,0x3C,0xD3,0xA4,0x85,0x2E,0xFB,0xEE,0x47,0x3B,0xEF,0x37,0x7F,
				0x93,0xAF,0x69,0x0C,0x71,0x31,0xDE,0x21,0x75,0xA0,0xAA,0xBA,0x7C,0x38,0x02,0xB7,
				0x81,0x01,0xFD,0xE7,0x1D,0xCC,0xCD,0xBD,0x1B,0x7A,0x2A,0xAD,0x66,0xBE,0x55,0x33,
				0x03,0xDB,0x88,0xB2,0x1E,0x4E,0xB9,0xE6,0xC2,0xF7,0xCB,0x7D,0xC9,0x62,0xC3,0xA6,
				0xDC,0xA7,0x50,0xB5,0x4B,0x94,0xC0,0x92,0x4C,0x11,0x5B,0x78,0xD9,0xB1,0xED,0x19,
				0xE9,0xA1,0x1C,0xB6,0x32,0x99,0xA3,0x76,0x9E,0x7B,0x6D,0x9A,0x30,0xD6,0xA9,0x25,
				0xC7,0xAE,0x96,0x35,0xD0,0xBB,0xD2,0xC8,0xA2,0x08,0xF3,0xD1,0x73,0xF4,0x48,0x2D,
				0x90,0xCA,0xE2,0x58,0xC1,0x18,0x52,0xFE,0xDF,0x68,0x98,0x54,0xEC,0x60,0x43,0x0F
			];
		
		//接收字节映射表
		private static const m_RecvByteMap:Array =	
			[
				0x51,0xA1,0x9E,0xB0,0x1E,0x83,0x1C,0x2D,0xE9,0x77,0x3D,0x13,0x93,0x10,0x45,0xFF,
				0x6D,0xC9,0x20,0x2F,0x1B,0x82,0x1A,0x7D,0xF5,0xCF,0x52,0xA8,0xD2,0xA4,0xB4,0x0B,
				0x31,0x97,0x57,0x19,0x34,0xDF,0x5B,0x41,0x58,0x49,0xAA,0x5F,0x0A,0xEF,0x88,0x01,
				0xDC,0x95,0xD4,0xAF,0x7B,0xE3,0x11,0x8E,0x9D,0x16,0x61,0x8C,0x84,0x3C,0x1F,0x5A,
				0x02,0x4F,0x39,0xFE,0x04,0x07,0x5C,0x8B,0xEE,0x66,0x33,0xC4,0xC8,0x59,0xB5,0x5D,
				0xC2,0x6C,0xF6,0x4D,0xFB,0xAE,0x4A,0x4B,0xF3,0x35,0x2C,0xCA,0x21,0x78,0x3B,0x03,
				0xFD,0x24,0xBD,0x25,0x37,0x29,0xAC,0x4E,0xF9,0x92,0x3A,0x32,0x4C,0xDA,0x06,0x5E,
				0x00,0x94,0x60,0xEC,0x17,0x98,0xD7,0x3E,0xCB,0x6A,0xA9,0xD9,0x9C,0xBB,0x08,0x8F,
				0x40,0xA0,0x6F,0x55,0x67,0x87,0x54,0x80,0xB2,0x36,0x47,0x22,0x44,0x63,0x05,0x6B,
				0xF0,0x0F,0xC7,0x90,0xC5,0x65,0xE2,0x64,0xFA,0xD5,0xDB,0x12,0x7A,0x0E,0xD8,0x7E,
				0x99,0xD1,0xE8,0xD6,0x86,0x27,0xBF,0xC1,0x6E,0xDE,0x9A,0x09,0x0D,0xAB,0xE1,0x91,
				0x56,0xCD,0xB3,0x76,0x0C,0xC3,0xD3,0x9F,0x42,0xB6,0x9B,0xE5,0x23,0xA7,0xAD,0x18,
				0xC6,0xF4,0xB8,0xBE,0x15,0x43,0x70,0xE0,0xE7,0xBC,0xF1,0xBA,0xA5,0xA6,0x53,0x75,
				0xE4,0xEB,0xE6,0x85,0x14,0x48,0xDD,0x38,0x2A,0xCC,0x7F,0xB1,0xC0,0x71,0x96,0xF8,
				0x3F,0x28,0xF2,0x69,0x74,0x68,0xB7,0xA3,0x50,0xD0,0x79,0x1D,0xFC,0xCE,0x8A,0x8D,
				0x2E,0x62,0x30,0xEA,0xED,0x2B,0x26,0xB9,0x81,0x7C,0x46,0x89,0x73,0xA2,0xF7,0x72
			];
		
		private static const g_dwPacketKey:Number=0xA55AA55A;
		
		public function Reset():void
		{
			m_cbSendRound = 0;
			m_cbRecvRound = 0;
		}
		
		//随机映射
		public function SeedRandMap(wSeed:uint):uint
		{
			var dwHold:int = wSeed;
			dwHold = (dwHold*241103+2533101)>>16;
			var ret:uint = dwHold & 0xffff;
			return ret;
		}
		
		//映射发送数据
		public function MapSendByte(cbData:int):uint
		{
			var cbMap:uint=m_SendByteMap[(cbData+m_cbSendRound)&0xff];
			m_cbSendRound=(m_cbSendRound+3) & 0xff;
			return cbMap;
		}
		
		//映射接收数据
		public function MapRecvByte(cbData:uint):uint
		{
			var cbMap:uint=(m_RecvByteMap[cbData]-m_cbRecvRound)&0xff;
			m_cbRecvRound=(m_cbRecvRound+3) & 0xff;
			return cbMap;
		}
		
		//生成随机数数组
		public static function randomArray():Array
		{
			var num_arr:Array = new Array();  
			var j:uint = 0;  
			var judge:uint = 0;  
			do {  
				var temp_num:uint = Math.round(Math.random()*100);  
				for (var i:uint = 0; i<num_arr.length; i++) {  
					var temp_n:uint = num_arr[i];  
					if (temp_num == temp_n) {  
						judge = 1;  
						break;  
					} else {  
						judge = 0;  
					}  
				}  
				if (judge == 0) {  
					num_arr.push(temp_num);  
					j++;  
				}  
			} while (j<100);  
			
			return num_arr;
		}
		
		//加密数据
		public function encrypt(packet:MsgPacket):ByteArrayPlus
		{
			var dataBap:ByteArrayPlus = new ByteArrayPlus();
			var encryptData:ByteArrayPlus = new ByteArrayPlus();
			dataBap.endian = Endian.LITTLE_ENDIAN;
			dataBap.writeShort(packet._id);
			dataBap.writeShort(packet._subid);
			dataBap.writeBytes(packet._data);
			
			var checkCode:uint = 0;
			var length:Number = dataBap.length;
			var byte:* = 0;
			encryptData.endian = Endian.LITTLE_ENDIAN;
			dataBap.position = 0;
			for(var i:uint=0;i<length;i++)
			{
				byte = dataBap.readByte();
				byte &= 0xff;
				checkCode += byte;
				var map:uint = MapSendByte(byte);
				encryptData.writeByte(map);
			}
			
			checkCode &= 0xff;
			
			var wEncryptSize:uint = encryptData.length;
			var wSnapCount:uint = 0;
			if ((wEncryptSize % BYTE_COUNT_32)!=0)
			{
				wSnapCount = BYTE_COUNT_32 - wEncryptSize % BYTE_COUNT_32;
				encryptData.length += wSnapCount;
			}
			
			//创建密钥
			var dwXorKey:uint=m_dwSendXorKey;
			if (m_dwSendPacketCount==0)
			{
				//随机映射种子
				dwXorKey = getTimer()*getTimer();
				dwXorKey = SeedRandMap(dwXorKey & 0xff);
				dwXorKey|=(uint(SeedRandMap((dwXorKey>>16&0xffff))))<<16;
				dwXorKey^=g_dwPacketKey;
				m_dwSendXorKey=dwXorKey;
				m_dwRecvXorKey=dwXorKey;
				
				m_dwSendXorKey = 2776409244;
				m_dwRecvXorKey = 2776409244;
				dwXorKey = 2776409244;
			}
			
			//加密数据
			var pdwXor:*=0;
			var bap1:ByteArrayPlus = new ByteArrayPlus();
			var wEncrypCount:int=(wEncryptSize+wSnapCount) / BYTE_COUNT_32;
			encryptData.position = 0;
			bap1.endian = Endian.LITTLE_ENDIAN;
			var v1:* = 0;
			for (i=0;i<wEncrypCount;i++)
			{
				pdwXor = encryptData.readUnsignedInt();
				//trace("v32:", pdwXor);
				pdwXor ^= dwXorKey;
				v1 = pdwXor & 0xffff;
				//trace("pwSeed01:", v1);
				dwXorKey = SeedRandMap(v1);
				//trace("dwXorKey=SeedRandMap(*pwSeed++):", dwXorKey);
				v1 = pdwXor>>16&0xffff;
				//trace("pwSeed02:", v1);
				v1 = (int)(SeedRandMap(v1));
				dwXorKey|=v1<<16;
				//trace("((uint32)SeedRandMap(*pwSeed++))<<16:", dwXorKey);
				dwXorKey^=g_dwPacketKey;
				bap1.writeInt(pdwXor);
				//trace("dwXorKey^=g_dwPacketKey:", dwXorKey);
			}
			
			bap1.position = 0;
			var retBap:ByteArrayPlus = new ByteArrayPlus();
			retBap.endian = Endian.LITTLE_ENDIAN;
			retBap.writeShort(0);
			retBap.writeByte(~checkCode+1);
			retBap.writeByte(MsgPacket.VERSION);
			retBap.writeShort(bap1.readShort());
			retBap.writeShort(bap1.readShort());
			if (m_dwSendPacketCount==0)
				retBap.writeUnsignedInt(m_dwSendXorKey);
			
			length = bap1.length;
			for(i = bap1.position;i<length;i++)
			{
				retBap.writeByte(bap1.readByte());
			}
			
			
			retBap.length -= wSnapCount;
			
			retBap.position = 0;
			retBap.writeShort(retBap.length);
			m_dwSendPacketCount++;
			m_dwSendXorKey=dwXorKey;
			
			return retBap;
		}
		
		//解密数据
		public function decrypt(data:ByteArrayPlus):MsgPacket
		{
			data.position = 0;
			var size:uint = data.readShort();
			var checkCode:uint = data.readByte() & 0xff;
			var version:uint = data.readByte() & 0xff;
			
			var wDataSize:uint = data.length - 4;
			var wSnapCount:uint=0;
			if ((wDataSize%BYTE_COUNT_32) != 0)
			{
				wSnapCount = BYTE_COUNT_32 - wDataSize%BYTE_COUNT_32;
			}
			
			//解密数据
			var dwXorKey:uint=m_dwRecvXorKey;
			var pdwXor:uint=0;
			var pwSeed1:uint=0;
			var pwSeed2:uint=0;
			var wEncrypCount:int=(wDataSize+wSnapCount)/4;
			var decryptData:ByteArrayPlus = new ByteArrayPlus();
			var v1:* = 0;
			for (var i:int=0;i<wEncrypCount;i++)
			{
				if ((i==(wEncrypCount-1))&&(wSnapCount>0))
				{
					var pcbKey4:uint = m_dwRecvXorKey&0xff;
					var pcbKey3:uint = m_dwRecvXorKey>>8&0xff;
					var pcbKey2:uint = m_dwRecvXorKey>>16 & 0xff;
					var pcbKey1:uint = m_dwRecvXorKey>>24 & 0xff;
					var arr:Array = [pcbKey1, pcbKey2, pcbKey3, pcbKey4];
					var tmpBap:ByteArrayPlus = new ByteArrayPlus;
					tmpBap.endian = Endian.LITTLE_ENDIAN;
					tmpBap.writeUnsignedInt(m_dwRecvXorKey);
					data.position += data.bytesAvailable;
					data.writeBytes(tmpBap, 4 - wSnapCount, wSnapCount);
					data.position -= 4;
					
				}
				pdwXor = data.readUnsignedInt();
				//trace("v01:",pdwXor);
				dwXorKey=SeedRandMap(pdwXor & 0xffff);
				//trace("dwXorKey01:", dwXorKey);
				v1 = pdwXor>>16&0xffff;
				v1 = SeedRandMap(v1);
				dwXorKey|=v1<<16;
				//trace("dwXorKey02:", dwXorKey);
				dwXorKey^=g_dwPacketKey;
				//trace("dwXorKey03:", dwXorKey);
				pdwXor^=m_dwRecvXorKey;
				//trace("v02:", uint(pdwXor));
				m_dwRecvXorKey=dwXorKey;
				decryptData.writeInt(pdwXor);
			}
			
			var byte:*;
			var retData:ByteArrayPlus = new ByteArrayPlus();
			decryptData.position = 0;
			decryptData.length -= wSnapCount;
			var length:uint = decryptData.length;
			//效验码与字节映射
			for(i = 0;i<length;i++)
			{
				byte = decryptData.readByte() & 0xff;
				//trace("cb01:", byte);
				byte = MapRecvByte(byte);
				//trace("cb02:", byte);
				checkCode += byte;
				checkCode &= 0xff;
				//trace("cbCheckCode:", checkCode);
				retData.writeByte(byte);
			}
			if (checkCode!=0) 
				return null;
			
			var packet:MsgPacket = new MsgPacket();
			retData.position = 0;
			packet._id = retData.readShort();
			packet._subid = retData.readShort();
			packet._data = retData;
			
			return packet;
		}

	}
}